/*
 * Problem.cpp
 *
 *  Created on: Sep 18, 2012
 *      Author: pedro
 */

#include "Problem.h"

/**
 * constroi um Problmea
 */
Problem::Problem(int size)
	: constraints(size)
{
	removedRows = new int [size];
	removedColumns = new int [size];

	nRemovedRows = 0;
	nRemovedColumns = 0;

	lowerBound = 0;

	for(int i = 0; i < size; ++i)
	{
		for(int j = 0; j < size; ++j)
		{
			constraints(i,j,AVALIABLE);
		}
	}
}


Problem::Problem(Problem &p)
	: constraints(p.constraints)
{

	removedRows = new int [constraints.getSize()];
	removedColumns = new int [constraints.getSize()];

	nRemovedRows = p.nRemovedRows;
	nRemovedColumns = p.nRemovedColumns;

	lowerBound = p.lowerBound;

	for(int i = 0; i < nRemovedRows; ++i)
	{
		removedRows[i] = p.removedRows[i];
		removedColumns[i] = p.removedColumns[i];
	}

}

Problem::Problem(const Problem &p)
	: constraints(p.constraints)
{

	removedRows = new int [constraints.getSize()];
	removedColumns = new int [constraints.getSize()];

	nRemovedRows = p.nRemovedRows;
	nRemovedColumns = p.nRemovedColumns;

	lowerBound = p.lowerBound;

	for(int i = 0; i < nRemovedRows; ++i)
	{
		removedRows[i] = p.removedRows[i];
		removedColumns[i] = p.removedColumns[i];
	}

}

/**
 * desaloca um problema
 */
Problem::~Problem()
{
	delete [] removedRows;
	delete [] removedColumns;
}

/**
 * adiciona uma restricao ao grafo inicial
 */
void Problem::addConstraint(int from, int to, int flag)
{

	if(flag == FIX_EDGE)
	{

		constraints(from,to,FIXED);
		insertionSort(ROW,from);
		insertionSort(COLUMN,to);
	}
	else if(flag == REMOVE_EDGE)
	{
		constraints(from,to,REMOVED);
	}
}

bool Problem::findRemovedRow(int row)
{
	for(int i = 0; i < nRemovedRows; ++i)
	{
		if(removedRows[i] == row)
			return true;
	}

	return false;
}

bool Problem::findRemovedColumn(int column)
{
	for(int i = 0; i < nRemovedColumns; ++i)
	{
		if(removedColumns[i] == column)
			return true;
	}

	return false;
}

bool Problem::checkFeasible(int cycleInf, int lastAddInf)
{
	int size = constraints.getSize();

	if(lastAddInf == FIXED && cycleInf == CYCLE)
		return false;

	if(lastAddInf == REMOVED)
		return true;

	for(int i = 0; i < size; ++i)
	{
		if(!checkRowIntegrity(i))
			return false;
		else if(!checkColumnIntegrity(i))
			return false;
	}

	for(int i = 0; i < nRemovedRows; ++i)
	{
		int from = i;
		int to = getCorrespondentFixedColumn(from);


	}

	return true;
}

int Problem::getRemovedRowsSize()
{
	return nRemovedRows;
}

int Problem::getRemovedColumnsSize()
{
	return nRemovedColumns;
}

bool Problem::checkRowIntegrity(int row)
{
	bool flag = false;
	for(int i = 0; i < constraints.getSize(); ++i)
	{
		if(flag == true && constraints(row,i) == FIXED)
			return false;
		if(constraints(row,i) == FIXED)
			flag = true;

	}
	return true;
}

bool Problem::checkColumnIntegrity(int col)
{

	bool flag = false;
	for(int i = 0; i < constraints.getSize(); ++i)
	{
		if(flag == true && constraints(col,i) == FIXED)
			return false;
		if(constraints(col,i) == FIXED)
			flag = true;

	}
	return true;
}

int Problem::getShiftColumns(int limit)
{
	int n = 0, aux;

	for(int i = 0; i < nRemovedColumns; ++i)
	{
		if(removedColumns[i] <= limit)
			n++;
		else
			return n;
	}

	return n;
}

int Problem::getCorrespondentFixedColumn(int row)
{
	for(int i = 0; i < constraints.getSize(); ++i)
	{
		if(constraints(row,i) == FIXED)
			return i;
	}
	return -1;
}

Graph & Problem::getConstraints()
{
	return constraints;
}


int Problem::getLowerBound()
{
	return lowerBound;
}

void Problem::setLowerBound(int lowerBound)
{
	this->lowerBound = lowerBound;
}

void Problem::insertionSort(int type, int value)
{
	int i;
	bool inside = false;
	int *size;
	int *data;


	if(type == ROW)
	{
		size = &nRemovedRows;
		data = removedRows;
	}
	else if(COLUMN)
	{
		size = &nRemovedColumns;
		data = removedColumns;
	}


	for(i = 0; i < *size; i++)
	{
		if(data[i] > value)
		{
			inside = true;
			(*size)++;
			for(int j = i; j < *size; ++j)
			{
				int aux = data[j];
				data[j] = value;
				value = aux;
			}
			break;
		}
	}
	if(i == *size && !inside)
	{
		data[i] = value;
		(*size)++;
	}

}

void Problem::send(int dest)
{
	COMM_WORLD.Send(&nRemovedColumns, 1, INT, dest, PROBLEM_TAG);

	COMM_WORLD.Send(&nRemovedRows, 1, INT, dest, PROBLEM_TAG);

	COMM_WORLD.Send(&lowerBound, 1, INT, dest, PROBLEM_TAG);

	COMM_WORLD.Send(removedColumns, nRemovedColumns, INT, dest, PROBLEM_TAG);

	COMM_WORLD.Send(removedRows, nRemovedRows, INT, dest, PROBLEM_TAG);

	constraints.send(dest);
}

void Problem::receive(int source)
{
	COMM_WORLD.Recv(&nRemovedColumns, 1, INT, source, PROBLEM_TAG);

	COMM_WORLD.Recv(&nRemovedRows, 1, INT, source, PROBLEM_TAG);

	COMM_WORLD.Recv(&lowerBound, 1, INT, source, PROBLEM_TAG);

	COMM_WORLD.Recv(removedColumns, nRemovedColumns, INT, source, PROBLEM_TAG);

	COMM_WORLD.Recv(removedRows, nRemovedRows, INT, source, PROBLEM_TAG);

	constraints.receive(source);

}

void Problem::printRemovedColumns()
{
	for(int i = 0; i < nRemovedColumns; ++i)
	{
		cout << removedColumns[i];
	}
}

void Problem::printRemovedRows()
{
	for(int i = 0; i < nRemovedRows; ++i)
	{
		cout << removedRows[i];
	}
}
